﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using System.Drawing.Printing;
using System.ComponentModel;

namespace TARLib
{
    public class Comanda : INotifyPropertyChanged
    {
        #region Costruttori
        public Comanda(int comandaID)
        {
            // Carica da DB una comanda
            SqlConnection conn = new SqlConnection(Database.GetDBConnectionString());
            SqlCommand cmd = new SqlCommand();
            cmd.Connection = conn;
            cmd.CommandText = "[Cucina].[SP_Comanda_S]";
            cmd.CommandType = System.Data.CommandType.StoredProcedure;
            cmd.Parameters.Add(new SqlParameter("@ComandaID", System.Data.SqlDbType.Int) { Value = comandaID });

            SqlDataReader dr = null;
            try
            {
                conn.Open();
                dr = cmd.ExecuteReader();

                if (dr.Read())
                {
                    ComandaID = comandaID;
                    TavoloAssegnato = dr["TavoloAssegnato"].ToString();
                    Codice = new CodiceComanda(dr["CodiceComanda"].ToString());
                    Note = dr["Note"] == DBNull.Value ? null : dr["Note"].ToString();
                    Sconto = (Decimal)dr["Sconto"];
                    DataOra = (DateTime)dr["DataOra"];
                    Autore = dr["Autore"].ToString();

                    CheckInAssociato = dr["CheckInID"] == DBNull.Value ? null : new ComandaCheckIn((int)dr["CheckInID"], comandaID, (DateTime)dr["CheckInDataOra"], dr["CheckInAutore"].ToString(), (bool)dr["CheckInEsito"]);

                    StampaRemotaAssociata = dr["StampaRemotaID"] == DBNull.Value ? null : new ComandaStampaRemota((int)dr["StampaRemotaID"], comandaID, dr["StampaRemotaStampante"].ToString(), (DateTime)dr["StampaRemotaDataOra"], dr["StampaRemotaAutore"].ToString(), (bool)dr["StampaRemotaEsito"]);

                    ConsegnaAssociata = dr["ConsegnaID"] == DBNull.Value ? null : new ComandaConsegna((int)dr["ConsegnaID"], comandaID, (DateTime)dr["ConsegnaDataOra"], dr["ConsegnaAutore"].ToString(), (bool)dr["ConsegnaEsito"]);

                    TimeStampMinCheckIn = (DateTime)dr["TimeStampMinCheckIn"];
                }
                else
                {
                    throw new Exception("Comanda ID " + comandaID.ToString() + " non trovata", null);
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                if (dr != null)
                {
                    dr.Close();
                    dr.Dispose();
                }
                cmd.Dispose();
                conn.Close();
                conn.Dispose();
            }

            // A questo punto carica le collection associate
            Prodotti = new ProdottoOrdinatoCollection();
            Prodotti.ListChanged += new ListChangedEventHandler(VociComanda_ListChanged);
            Prodotti.CaricaDaComandaID(comandaID);

            Log = new ComandaLogCollection();
            Log.CaricaDaComandaID(comandaID);

            Vassoi = new VassoioCollection(comandaID);
        }

        public Comanda(int? comandaID, ProdottoOrdinatoCollection prodotti, string tavoloAssegnato, CodiceComanda codice, string note, Decimal sconto, DateTime dataOra, string autore, ComandaLogCollection log, ComandaCheckIn checkInAssociato, ComandaStampaRemota stampaRemotaAssociata, ComandaConsegna consegnaAssociata, VassoioCollection vassoi, DateTime timeStampMinCheckIn)
        {
            ComandaID = comandaID;
            Prodotti = prodotti;
            TavoloAssegnato = tavoloAssegnato;
            Codice = codice;
            Note = note;
            Sconto = sconto;
            DataOra = dataOra;
            Autore = autore;
            Log = log;
            CheckInAssociato = checkInAssociato;
            StampaRemotaAssociata = stampaRemotaAssociata;
            ConsegnaAssociata = consegnaAssociata;
            Vassoi = vassoi;
            TimeStampMinCheckIn = timeStampMinCheckIn;

            Prodotti.ListChanged += new ListChangedEventHandler(VociComanda_ListChanged);
        }

        void VociComanda_ListChanged(object sender, ListChangedEventArgs e)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs("VociComanda"));
        }
        #endregion

        #region Proprietà
        public int? ComandaID { get; set; }
        public ProdottoOrdinatoCollection Prodotti { get; set; }
        public string TavoloAssegnato { get; set; }
        public CodiceComanda Codice { get; set; }
        public string Note { get; set; }
        public Decimal Sconto { get; set; }
        public DateTime DataOra { get; set; }
        public string Autore { get; set; }
        public ComandaLogCollection Log { get; set; }
        public VassoioCollection Vassoi { get; set; }
        public DateTime TimeStampMinCheckIn { get; set; }
        #endregion

        #region Proprietà calcolate
        public PuntoDistribuzione PuntoDiDistribuzione
        {
            get
            {
                if (Prodotti.Count == 0)
                    return null;
                else
                {
                    if (Prodotti.Select(o => o.PuntoDiDistribuzione).Any(o => o.PuntoDistribuzioneID != Prodotti.Last().PuntoDiDistribuzione.PuntoDistribuzioneID))
                    {
                        throw new Exception("Più punti di distribuzione definiti per la comanda " + ComandaID.ToString());
                    }
                    else
                    {
                        return Prodotti.Last().PuntoDiDistribuzione;
                    }
                }
            }
        }

        public Decimal TotaleLordo
        {
            get
            {
                return Prodotti.Sum(o => o.PrezzoVendita);
            }
        }

        public Decimal Totale
        {
            get
            {
                return TotaleLordo - Sconto;
            }
        }

        public int NumeroProdotti
        {
            get
            {
                return Prodotti.Count;
            }
        }

        public VoceComandaCollection VociComanda
        {
            get
            {
                VoceComandaCollection retValue = new VoceComandaCollection();

                foreach (ProdottoOrdinato po in Prodotti)
                {
                    // Raggruppa per "Nome prodotto / Note"
                    if (retValue.Any(o => o.NomeProdotto == po.Nome && o.Note == po.Note))
                    {
                        retValue.Where(o => o.NomeProdotto == po.Nome && o.Note == po.Note).First().Quantita++;
                        retValue.Where(o => o.NomeProdotto == po.Nome && o.Note == po.Note).First().SubTotale += po.PrezzoVendita;
                    }
                    else
                    {
                        retValue.Add(new VoceComanda(1, po.Nome, po.Note, po.PrezzoVendita));
                    }
                }

                return retValue;
            }
        }

        public StatoComanda StatoCorrente
        {
            get
            {
                if (!ComandaID.HasValue)
                    return StatoComanda.InAttesaDiSalvataggio;
                else if (!IsCheckInRichiesto && !IsStampaRemotaRichiesta && !IsConsegnaRichiesta)
                    return StatoComanda.SalvataggioEffettuato;
                else if (IsCheckInRichiesto && CheckInAssociato == null && StampaRemotaAssociata == null & ConsegnaAssociata == null)
                    return StatoComanda.InAttesaDiCheckIn;
                else if (IsCheckInRichiesto && CheckInAssociato != null && !IsStampaRemotaRichiesta && !IsConsegnaRichiesta)
                    return StatoComanda.CheckInEffettuato;
                else if (IsStampaRemotaRichiesta && StampaRemotaAssociata == null && ConsegnaAssociata == null)
                    return StatoComanda.InAttesaDiStampaRemota;
                else if (IsStampaRemotaRichiesta && StampaRemotaAssociata != null && !IsConsegnaRichiesta)
                    return StatoComanda.StampaRemotaEffettuata;
                else if (IsConsegnaRichiesta && ConsegnaAssociata == null)
                    return StatoComanda.InAttesaDiConsegna;
                else if (IsConsegnaRichiesta && ConsegnaAssociata != null)
                    return StatoComanda.ConsegnaEffettuata;
                else return StatoComanda.NessunoStato;
            }
        }

        public StatoComanda StatoSuccessivo
        {
            get
            {
                switch (StatoCorrente)
                {
                    case StatoComanda.InAttesaDiSalvataggio:
                        if (IsCheckInRichiesto)
                            return StatoComanda.InAttesaDiCheckIn;
                        else if (IsStampaRemotaRichiesta)
                            return StatoComanda.InAttesaDiStampaRemota;
                        else if (IsConsegnaRichiesta)
                            return StatoComanda.InAttesaDiConsegna;
                        else
                            return StatoComanda.SalvataggioEffettuato;
                    case StatoComanda.SalvataggioEffettuato:
                        return StatoComanda.NessunoStato;
                    case StatoComanda.InAttesaDiCheckIn:
                        if (IsStampaRemotaRichiesta)
                            return StatoComanda.InAttesaDiStampaRemota;
                        else if (IsConsegnaRichiesta)
                            return StatoComanda.InAttesaDiConsegna;
                        else
                            return StatoComanda.CheckInEffettuato;
                    case StatoComanda.CheckInEffettuato:
                        return StatoComanda.NessunoStato;
                    case StatoComanda.InAttesaDiStampaRemota:
                        if (IsConsegnaRichiesta)
                            return StatoComanda.InAttesaDiConsegna;
                        else
                            return StatoComanda.StampaRemotaEffettuata;
                    case StatoComanda.StampaRemotaEffettuata:
                        return StatoComanda.NessunoStato;
                    case StatoComanda.InAttesaDiConsegna:
                        return StatoComanda.ConsegnaEffettuata;
                    case StatoComanda.ConsegnaEffettuata:
                        return StatoComanda.NessunoStato;
                    case StatoComanda.NessunoStato:
                        return StatoComanda.NessunoStato;
                    default:
                        return StatoComanda.NessunoStato;
                }
            }
        }

        public TimeSpan Attesa
        {
            get
            {
                return DateTime.Now.Subtract(DataOra);
            }
        }

        public int AttesaInMinuti
        {
            get
            {
                return (int)Attesa.TotalMinutes;
            }
        }

        public string DataOraFormattata
        {
            get
            {
                return String.Format("{0:dd/MM/yyyy HH:mm}", DataOra);
            }
        }

        public string DescrizioneCompleta
        {
            get
            {
                string retValue = "";

                retValue += "COMANDA " + PuntoDiDistribuzione.Descrizione.ToUpper() + " " + Codice.CodiceRaw + "\n";
                retValue += "Stato corrente: " + StatoCorrente.ToString() + "\n";
                retValue += "Creata il: " + DataOraFormattata + "\n";
                retValue += "\nPRODOTTI: " + NumeroProdotti + "\n";
                foreach (VoceComanda v in VociComanda)
                {
                    retValue += String.Format("   {0} x {1} {2}\n", v.Quantita, v.NomeProdotto, v.Note);
                }

                return retValue;
            }
        }

        public bool IsCheckInAttivo
        {
            get
            {
                return IsCheckInRichiesto && CheckInAssociato == null;
            }
        }

        public string AttesaAlCheckInAutomatico
        {
            get
            {
                return "-" + ((int)TimeStampMinCheckIn.Subtract(DateTime.Now).TotalMinutes).ToString() + " minuti";
            }
        }
        #endregion

        #region Flusso esecuzione
        public bool IsCheckInRichiesto { get { return PuntoDiDistribuzione == null ? false : PuntoDiDistribuzione.IsCheckInRichiesto; } }
        public ComandaCheckIn CheckInAssociato { get; set; }
        public bool IsStampaRemotaRichiesta { get { return PuntoDiDistribuzione == null ? false : PuntoDiDistribuzione.IsStampaRemotaRichiesta; } }
        public ComandaStampaRemota StampaRemotaAssociata { get; set; }
        public bool IsConsegnaRichiesta { get { return PuntoDiDistribuzione == null ? false : PuntoDiDistribuzione.IsConsegnaRichiesta; } }
        public ComandaConsegna ConsegnaAssociata { get; set; }
        #endregion

        public void Salva(Guid ordineID)
        {
            // Crea transazione e chiama l'altro metodo
            using (SqlConnection connection = new SqlConnection(Database.GetDBConnectionString()))
            {
                connection.Open();

                SqlTransaction trans;
                trans = connection.BeginTransaction();

                try
                {
                    Salva(ordineID, trans);
                    trans.Commit();
                }
                catch (Exception ex)
                {
                    trans.Rollback();

                    throw ex;
                }
            }
        }

        public void Salva(Guid ordineID, SqlTransaction trans)
        {
            if (ComandaID.HasValue)
            {
                // E' una procedura di update
                // Aggiorna l'orario
                this.DataOra = DateTime.Now;

                // Salvataggio su DB
                SqlCommand cmd = new SqlCommand();
                cmd.Transaction = trans;
                cmd.Connection = trans.Connection;
                cmd.CommandText = "[Cucina].[SP_Comanda_U]";
                cmd.CommandType = System.Data.CommandType.StoredProcedure;

                cmd.Parameters.Add(new SqlParameter("@ComandaID", System.Data.SqlDbType.Int) { Value = ComandaID.Value });
                cmd.Parameters.Add(new SqlParameter("@PuntoDistribuzioneID", System.Data.SqlDbType.Int) { Value = PuntoDiDistribuzione.PuntoDistribuzioneID });

                cmd.Parameters.Add(new SqlParameter("@TavoloAssegnato", System.Data.SqlDbType.NVarChar, 20));
                if (TavoloAssegnato == null)
                    cmd.Parameters["@TavoloAssegnato"].Value = DBNull.Value;
                else
                    cmd.Parameters["@TavoloAssegnato"].Value = TavoloAssegnato;

                cmd.Parameters.Add(new SqlParameter("@Note", System.Data.SqlDbType.NVarChar, 4000));
                if (Note == null)
                    cmd.Parameters["@Note"].Value = DBNull.Value;
                else
                    cmd.Parameters["@Note"].Value = Note;

                cmd.Parameters.Add(new SqlParameter("@Sconto", System.Data.SqlDbType.Decimal) { Value = Sconto, Precision = 10, Scale = 2 });
                cmd.Parameters.Add(new SqlParameter("@DataOra", System.Data.SqlDbType.DateTime) { Value = DataOra });
                cmd.Parameters.Add(new SqlParameter("@Autore", System.Data.SqlDbType.NVarChar, 200) { Value = Autore });
                cmd.Parameters.Add(new SqlParameter("@IsCheckInRichiesto", System.Data.SqlDbType.Bit) { Value = IsCheckInRichiesto });
                cmd.Parameters.Add(new SqlParameter("@IsStampaRemotaRichiesta", System.Data.SqlDbType.Bit) { Value = IsStampaRemotaRichiesta });
                cmd.Parameters.Add(new SqlParameter("@IsConsegnaRichiesta", System.Data.SqlDbType.Bit) { Value = IsConsegnaRichiesta });
                cmd.Parameters.Add(new SqlParameter("@TimeStampMinCheckIn", System.Data.SqlDbType.DateTime) { Value = TimeStampMinCheckIn });

                try
                {
                    cmd.ExecuteNonQuery();
                }
                catch (Exception ex)
                {
                    throw ex;
                }
                finally
                {
                    cmd.Dispose();
                }

                // Salva le collection associate
                Prodotti.SalvaByComandaID(ComandaID.Value, trans);
                // Log.SalvaByComandaID(ComandaID.Value, trans)
            }
            else
            {
                // E' una procedura di salvataggio
                // Aggiorna l'orario
                this.DataOra = DateTime.Now;

                // Salvataggio su DB
                SqlCommand cmd = new SqlCommand();
                cmd.Transaction = trans;
                cmd.Connection = trans.Connection;
                cmd.CommandText = "[Cucina].[SP_Comanda_I]";
                cmd.CommandType = System.Data.CommandType.StoredProcedure;

                cmd.Parameters.Add(new SqlParameter("@ComandaID", System.Data.SqlDbType.Int) { Direction = System.Data.ParameterDirection.Output });
                cmd.Parameters.Add(new SqlParameter("@CodiceComanda", System.Data.SqlDbType.NVarChar, 20) { Direction = System.Data.ParameterDirection.Output });

                cmd.Parameters.Add(new SqlParameter("@OrdineID", System.Data.SqlDbType.UniqueIdentifier) { Value = ordineID });
                cmd.Parameters.Add(new SqlParameter("@PuntoDistribuzioneID", System.Data.SqlDbType.Int) { Value = PuntoDiDistribuzione.PuntoDistribuzioneID });

                cmd.Parameters.Add(new SqlParameter("@TavoloAssegnato", System.Data.SqlDbType.NVarChar, 20));
                if (TavoloAssegnato == null)
                    cmd.Parameters["@TavoloAssegnato"].Value = DBNull.Value;
                else
                    cmd.Parameters["@TavoloAssegnato"].Value = TavoloAssegnato;

                cmd.Parameters.Add(new SqlParameter("@Note", System.Data.SqlDbType.NVarChar, 4000));
                if (Note == null)
                    cmd.Parameters["@Note"].Value = DBNull.Value;
                else
                    cmd.Parameters["@Note"].Value = Note;

                cmd.Parameters.Add(new SqlParameter("@Sconto", System.Data.SqlDbType.Decimal) { Value = Sconto, Precision = 10, Scale = 2 });
                cmd.Parameters.Add(new SqlParameter("@DataOra", System.Data.SqlDbType.DateTime) { Value = DataOra });
                cmd.Parameters.Add(new SqlParameter("@Autore", System.Data.SqlDbType.NVarChar, 200) { Value = Autore });
                cmd.Parameters.Add(new SqlParameter("@IsCheckInRichiesto", System.Data.SqlDbType.Bit) { Value = IsCheckInRichiesto });
                cmd.Parameters.Add(new SqlParameter("@IsStampaRemotaRichiesta", System.Data.SqlDbType.Bit) { Value = IsStampaRemotaRichiesta });
                cmd.Parameters.Add(new SqlParameter("@IsConsegnaRichiesta", System.Data.SqlDbType.Bit) { Value = IsConsegnaRichiesta });
                cmd.Parameters.Add(new SqlParameter("@TimeStampMinCheckIn", System.Data.SqlDbType.DateTime) { Value = TimeStampMinCheckIn });

                try
                {
                    cmd.ExecuteNonQuery();
                    ComandaID = (int)cmd.Parameters["@ComandaID"].Value;
                    Codice = new CodiceComanda(cmd.Parameters["@CodiceComanda"].Value.ToString());
                }
                catch (Exception ex)
                {
                    throw ex;
                }
                finally
                {
                    cmd.Dispose();
                }

                // Salva le collection associate
                Prodotti.SalvaByComandaID(ComandaID.Value, trans);
                // Log.SalvaByComandaID(ComandaID.Value, trans);
            }

            // Crea i vassoi e salva su DB
            Vassoi = new VassoioCollection(ComandaID.Value, PuntoDiDistribuzione.PuntoDistribuzioneID, TavoloAssegnato, Codice.CodiceRaw, Note, DataOra, Autore, Prodotti);
            Vassoi.Salva(trans);
        }

        public void Blocca(int userID, DateTime dataOra)
        {
            // Salvataggio su DB
            if (ComandaID.HasValue)
            {
                using (SqlConnection connection = new SqlConnection(Database.GetDBConnectionString()))
                {
                    connection.Open();
                    SqlCommand cmd = new SqlCommand();
                    cmd.Connection = connection;
                    cmd.CommandText = "[Cucina].[SP_ComandaLocked_I]";
                    cmd.CommandType = System.Data.CommandType.StoredProcedure;

                    cmd.Parameters.Add(new SqlParameter("@ComandaID", System.Data.SqlDbType.Int) { Value = ComandaID });
                    cmd.Parameters.Add(new SqlParameter("@TimeStamp_Insert", System.Data.SqlDbType.DateTime) { Value = dataOra });
                    cmd.Parameters.Add(new SqlParameter("@UserID", System.Data.SqlDbType.NVarChar, 200) { Value = userID });

                    try
                    {
                        cmd.ExecuteNonQuery();
                    }
                    catch (Exception ex)
                    {
                        throw ex;
                    }
                    finally
                    {
                        connection.Close();
                        cmd.Dispose();
                    }
                }
            }
            else
            {
                throw new Exception("Impossibile bloccare comande non ancora salvate");
            }
        }

        public void Sblocca()
        {
            // Salvataggio su DB
            if (ComandaID.HasValue)
            {
                using (SqlConnection connection = new SqlConnection(Database.GetDBConnectionString()))
                {
                    connection.Open();
                    SqlCommand cmd = new SqlCommand();
                    cmd.Connection = connection;
                    cmd.CommandText = "[Cucina].[SP_ComandaLocked_D]";
                    cmd.CommandType = System.Data.CommandType.StoredProcedure;

                    cmd.Parameters.Add(new SqlParameter("@ComandaID", System.Data.SqlDbType.Int) { Value = ComandaID });

                    try
                    {
                        cmd.ExecuteNonQuery();
                    }
                    catch (Exception ex)
                    {
                        throw ex;
                    }
                    finally
                    {
                        connection.Close();
                        cmd.Dispose();
                    }
                }
            }
            else
            {
                throw new Exception("Impossibile sbloccare comande non ancora salvate");
            }
        }

        public void Elimina(int userID, DateTime dataOra)
        {
            // Salvataggio su DB
            if (ComandaID.HasValue)
            {
                using (SqlConnection connection = new SqlConnection(Database.GetDBConnectionString()))
                {
                    connection.Open();
                    SqlCommand cmd = new SqlCommand();
                    cmd.Connection = connection;
                    cmd.CommandText = "[Cucina].[SP_Comanda_D]";
                    cmd.CommandType = System.Data.CommandType.StoredProcedure;

                    cmd.Parameters.Add(new SqlParameter("@ComandaID", System.Data.SqlDbType.Int) { Value = ComandaID });
                    cmd.Parameters.Add(new SqlParameter("@UserID", System.Data.SqlDbType.Int) { Value = userID });
                    cmd.Parameters.Add(new SqlParameter("@TimeStamp_Insert", System.Data.SqlDbType.DateTime) { Value = dataOra });

                    try
                    {
                        cmd.ExecuteNonQuery();
                    }
                    catch (Exception ex)
                    {
                        throw ex;
                    }
                    finally
                    {
                        connection.Close();
                        cmd.Dispose();
                    }
                }
            }
            else
            {
                throw new Exception("Impossibile eliminare comande non ancora salvate");
            }
        }

        public void SetChecked(DateTime dataOra, string autore, bool esito)
        {
            // Salvataggio su DB
            if (ComandaID.HasValue)
            {
                using (SqlConnection connection = new SqlConnection(Database.GetDBConnectionString()))
                {
                    connection.Open();
                    SqlCommand cmd = new SqlCommand();
                    cmd.Connection = connection;
                    cmd.CommandText = "[Cucina].[SP_ComandaCheckIn_I]";
                    cmd.CommandType = System.Data.CommandType.StoredProcedure;

                    cmd.Parameters.Add(new SqlParameter("@ComandaCheckInID", System.Data.SqlDbType.Int) { Direction = System.Data.ParameterDirection.Output });

                    cmd.Parameters.Add(new SqlParameter("@ComandaID", System.Data.SqlDbType.Int) { Value = ComandaID });
                    cmd.Parameters.Add(new SqlParameter("@DataOra", System.Data.SqlDbType.DateTime) { Value = dataOra });
                    cmd.Parameters.Add(new SqlParameter("@Autore", System.Data.SqlDbType.NVarChar, 200) { Value = autore });
                    cmd.Parameters.Add(new SqlParameter("@Esito", System.Data.SqlDbType.Bit) { Value = esito });

                    try
                    {
                        cmd.ExecuteNonQuery();
                        CheckInAssociato = new ComandaCheckIn(
                            (int)cmd.Parameters["@ComandaCheckInID"].Value,
                            ComandaID.Value,
                            dataOra,
                            autore,
                            esito);
                    }
                    catch (Exception ex)
                    {
                        throw ex;
                    }
                    finally
                    {
                        connection.Close();
                        cmd.Dispose();
                    }
                }
            }
            else
            {
                throw new Exception("Impossibile effettuare check-in di comande non ancora salvate");
            }
        }

        public void SetPrinted(DateTime dataOra, string autore, bool esito, string stampante)
        {
            // Salvataggio su DB
            if (ComandaID.HasValue)
            {
                using (SqlConnection connection = new SqlConnection(Database.GetDBConnectionString()))
                {
                    connection.Open();
                    SqlCommand cmd = new SqlCommand();
                    cmd.Connection = connection;
                    cmd.CommandText = "[Cucina].[SP_ComandaStampaRemota_I]";
                    cmd.CommandType = System.Data.CommandType.StoredProcedure;

                    cmd.Parameters.Add(new SqlParameter("@ComandaStampaRemotaID", System.Data.SqlDbType.Int) { Direction = System.Data.ParameterDirection.Output });

                    cmd.Parameters.Add(new SqlParameter("@ComandaID", System.Data.SqlDbType.Int) { Value = ComandaID });
                    cmd.Parameters.Add(new SqlParameter("@DataOra", System.Data.SqlDbType.DateTime) { Value = dataOra });
                    cmd.Parameters.Add(new SqlParameter("@Autore", System.Data.SqlDbType.NVarChar, 200) { Value = autore });
                    cmd.Parameters.Add(new SqlParameter("@Stampante", System.Data.SqlDbType.NVarChar, 200) { Value = stampante });
                    cmd.Parameters.Add(new SqlParameter("@Esito", System.Data.SqlDbType.Bit) { Value = esito });

                    try
                    {
                        cmd.ExecuteNonQuery();
                        StampaRemotaAssociata = new ComandaStampaRemota(
                            (int)cmd.Parameters["@ComandaStampaRemotaID"].Value,
                            ComandaID.Value,
                            stampante,
                            dataOra,
                            autore,
                            esito);
                    }
                    catch (Exception ex)
                    {
                        throw ex;
                    }
                    finally
                    {
                        connection.Close();
                        cmd.Dispose();
                    }
                }
            }
            else
            {
                throw new Exception("Impossibile effettuare stampa di comande non ancora salvate");
            }
        }

        public void SetDelivered(DateTime dataOra, string autore, bool esito)
        {
            if (ComandaID.HasValue)
            {
                using (SqlConnection connection = new SqlConnection(Database.GetDBConnectionString()))
                {
                    connection.Open();
                    SqlCommand cmd = new SqlCommand();
                    cmd.Connection = connection;
                    cmd.CommandText = "[Cucina].[SP_ComandaConsegna_I]";
                    cmd.CommandType = System.Data.CommandType.StoredProcedure;

                    cmd.Parameters.Add(new SqlParameter("@ComandaConsegnaID", System.Data.SqlDbType.Int) { Direction = System.Data.ParameterDirection.Output });

                    cmd.Parameters.Add(new SqlParameter("@ComandaID", System.Data.SqlDbType.Int) { Value = ComandaID });
                    cmd.Parameters.Add(new SqlParameter("@DataOra", System.Data.SqlDbType.DateTime) { Value = dataOra });
                    cmd.Parameters.Add(new SqlParameter("@Autore", System.Data.SqlDbType.NVarChar, 200) { Value = autore });
                    cmd.Parameters.Add(new SqlParameter("@Esito", System.Data.SqlDbType.Bit) { Value = esito });

                    try
                    {
                        cmd.ExecuteNonQuery();
                        ConsegnaAssociata = new ComandaConsegna(
                            (int)cmd.Parameters["@ComandaConsegnaID"].Value,
                            ComandaID.Value,
                            dataOra,
                            autore,
                            esito);
                    }
                    catch (Exception ex)
                    {
                        throw ex;
                    }
                    finally
                    {
                        connection.Close();
                        cmd.Dispose();
                    }
                }
            }
            else
            {
                throw new Exception("Impossibile effettuare consegna di comande non ancora salvate");
            }
        }

        public void Refresh()
        {
            // Aggiorna (refresh) la comanda
            if (this.ComandaID.HasValue)
            {
                SqlConnection conn = new SqlConnection(Database.GetDBConnectionString());
                SqlCommand cmd = new SqlCommand();
                cmd.Connection = conn;
                cmd.CommandText = "[Cucina].[SP_Comanda_S]";
                cmd.CommandType = System.Data.CommandType.StoredProcedure;
                cmd.Parameters.Add(new SqlParameter("@ComandaID", System.Data.SqlDbType.Int) { Value = this.ComandaID });

                SqlDataReader dr = null;
                try
                {
                    conn.Open();
                    dr = cmd.ExecuteReader();

                    if (dr.Read())
                    {
                        TavoloAssegnato = dr["TavoloAssegnato"].ToString();
                        Codice = new CodiceComanda(dr["CodiceComanda"].ToString());
                        Note = dr["Note"] == DBNull.Value ? null : dr["Note"].ToString();
                        Sconto = (Decimal)dr["Sconto"];
                        DataOra = (DateTime)dr["DataOra"];
                        Autore = dr["Autore"].ToString();

                        CheckInAssociato = dr["CheckInID"] == DBNull.Value ? null : new ComandaCheckIn((int)dr["CheckInID"], this.ComandaID.Value, (DateTime)dr["CheckInDataOra"], dr["CheckInAutore"].ToString(), (bool)dr["CheckInEsito"]);

                        StampaRemotaAssociata = dr["StampaRemotaID"] == DBNull.Value ? null : new ComandaStampaRemota((int)dr["StampaRemotaID"], this.ComandaID.Value, dr["StampaRemotaStampante"].ToString(), (DateTime)dr["StampaRemotaDataOra"], dr["StampaRemotaAutore"].ToString(), (bool)dr["StampaRemotaEsito"]);

                        ConsegnaAssociata = dr["ConsegnaID"] == DBNull.Value ? null : new ComandaConsegna((int)dr["ConsegnaID"], this.ComandaID.Value, (DateTime)dr["ConsegnaDataOra"], dr["ConsegnaAutore"].ToString(), (bool)dr["ConsegnaEsito"]);

                        TimeStampMinCheckIn = (DateTime)dr["TimeStampMinCheckIn"];
                    }
                    else
                    {
                        throw new Exception("Comanda ID " + this.ComandaID.ToString() + " non trovata", null);
                    }
                }
                catch (Exception ex)
                {
                    throw ex;
                }
                finally
                {
                    if (dr != null)
                    {
                        dr.Close();
                        dr.Dispose();
                    }
                    cmd.Dispose();
                    conn.Close();
                    conn.Dispose();
                }

                // A questo punto carica le collection associate
                Prodotti = new ProdottoOrdinatoCollection();
                Prodotti.ListChanged += new ListChangedEventHandler(VociComanda_ListChanged);
                Prodotti.CaricaDaComandaID(this.ComandaID.Value);

                Log = new ComandaLogCollection();
                Log.CaricaDaComandaID(this.ComandaID.Value);

                Vassoi = new VassoioCollection(this.ComandaID.Value);
            }
        }
        // Per la stampa
        public void OttieniStampa(ref PrintPageEventArgs e, TipoStampa tipoStampa)
        {
            switch (tipoStampa)
            {
                case TipoStampa.RicevutaCassa:
                    StampaBigliettoCassa(e);
                    break;
                case TipoStampa.ComandaRistorante:
                    StampaComandaRistorante(e);
                    break;
                default:
                    break;
            }
        }

        private void StampaBigliettoCassa(PrintPageEventArgs e)
        {
            System.Drawing.Font EtichettaFont = new System.Drawing.Font("Arial", 12);
            System.Drawing.Font PuntoDistribuzioneFont = new System.Drawing.Font("Arial", 16, System.Drawing.FontStyle.Bold);
            System.Drawing.Font EvidenziatoFont = new System.Drawing.Font("Arial", 13, System.Drawing.FontStyle.Bold);
            System.Drawing.Font NoteFont = new System.Drawing.Font("Courier New", 10, System.Drawing.FontStyle.Italic);
            System.Drawing.Font ValoreEquiFont = new System.Drawing.Font("Courier New", 14);
            System.Drawing.Font ValoreFont = new System.Drawing.Font("Arial", 14);
            System.Drawing.Font ValoreFontSmall = new System.Drawing.Font("Arial", 11);

            // 1) Header biglietto [ComandaID | CodiceComanda | Barcode]
            e.Graphics.DrawString("COMANDA: ", EtichettaFont, System.Drawing.Brushes.Black, new System.Drawing.PointF(5, 5));
            e.Graphics.DrawString(ComandaID.ToString().PadLeft(6, '0'), ValoreEquiFont, System.Drawing.Brushes.Black, new System.Drawing.PointF(110, 5));
            e.Graphics.DrawString(Codice.CodiceRaw, new System.Drawing.Font("Arial Black", 30), System.Drawing.Brushes.Red, new System.Drawing.PointF(30, 15));
            iTextSharp.text.pdf.Barcode128 b = new iTextSharp.text.pdf.Barcode128();
            b.Code = new TARLib.Operazioni.Operazione_Comanda(ComandaID.Value).BarcodeString;
            System.Drawing.Image image = b.CreateDrawingImage(System.Drawing.Color.Black, System.Drawing.Color.White);
            e.Graphics.DrawImage(image, 220, 5, 150, 50);
            e.Graphics.DrawLine(System.Drawing.Pens.Black, new System.Drawing.Point(0, 80), new System.Drawing.Point(390, 80));

            // 2) Punto di distribuzione ["Ristorante"]
            e.Graphics.DrawString(PuntoDiDistribuzione.Descrizione.ToUpper(), PuntoDistribuzioneFont, System.Drawing.Brushes.Black, new System.Drawing.PointF(10, 80));

            e.Graphics.DrawLine(System.Drawing.Pens.Black, new System.Drawing.Point(0, 110), new System.Drawing.Point(390, 110));

            // 3) Area con i prodotti ["Quantita | Descrizione | Importo"]
            // 0, 120 --> 390, 420
            int i = 0;
            if (VociComanda.Count >= 1)
            {
                // Quante comande hanno delle note?
                int NNote = VociComanda.Where(o => !String.IsNullOrEmpty(o.Note)).Count();

                int stepHeight = (300 / (VociComanda.Count + NNote / 2)) < 35 ? (300 / (VociComanda.Count + NNote / 2)) : 35;
                foreach (VoceComanda v in VociComanda)
                {
                    e.Graphics.DrawString(v.Quantita.ToString().PadLeft(2, ' '), ValoreEquiFont, System.Drawing.Brushes.Black, new System.Drawing.PointF(2, 130 + stepHeight * i));

                    e.Graphics.DrawString(v.NomeProdotto, ValoreFont, System.Drawing.Brushes.Black, new System.Drawing.PointF(40, 130 + stepHeight * i));

                    e.Graphics.DrawString(String.Format("{0:0.00} €", v.SubTotale).PadLeft(8, ' '), ValoreEquiFont, System.Drawing.Brushes.Black, new System.Drawing.PointF(280, 130 + stepHeight * i));

                    if (!String.IsNullOrEmpty(v.Note))
                    {
                        e.Graphics.DrawString(v.Note, NoteFont, System.Drawing.Brushes.Black, new System.Drawing.PointF(45, 130 + stepHeight * ((float)i + (float)0.5)));
                    }

                    i++;
                }
            }

            // 4) Footer ["Ritiro: consegna ai tavoli (Tavolo 10) | DataOra biglietto | Totale biglietto"]

            // Note
            if (!String.IsNullOrEmpty(Note))
            {
                e.Graphics.FillRectangle(System.Drawing.Brushes.LightGray, new System.Drawing.Rectangle(2, 450, 386, 20));
                e.Graphics.DrawString(Note.ToLower(), EvidenziatoFont, System.Drawing.Brushes.Black, new System.Drawing.PointF(5, 451));
            }

            e.Graphics.DrawString("CONSEGNA:", ValoreFontSmall, System.Drawing.Brushes.Black, new System.Drawing.PointF(2, 470));
            string tipoConsegna = "";
            if (!String.IsNullOrEmpty(TavoloAssegnato) && IsStampaRemotaRichiesta)
            {
                // Consegna al tavolo
                tipoConsegna = "Al tavolo n° " + TavoloAssegnato;
            }
            else if (IsCheckInRichiesto)
            {
                // Check-in richiesto (Ristorante cascine)
                // tipoConsegna = "Check-in alla chiamata della lettera " + Codice.CodiceRaw[0];
                // TODO: occorre generalizzarlo (adesso è custom per il gran premio
                tipoConsegna = "SELF SERVICE";
            }
            else if (IsStampaRemotaRichiesta)
            {
                // No check-in, stampa remota (Pizzeria)
                // tipoConsegna = "Chiamata del codice " + Codice.CodiceRaw + " per consegna";
                // TODO: occorre generalizzarlo (adesso è custom per il gran premio
                tipoConsegna = "SELF SERVICE";
            }
            else
            {
                // Self service
                tipoConsegna = "SELF SERVICE";
            }
            e.Graphics.DrawString(tipoConsegna, ValoreFontSmall, System.Drawing.Brushes.Black, new System.Drawing.PointF(100, 470));

            e.Graphics.DrawLine(System.Drawing.Pens.Black, new System.Drawing.Point(0, 470), new System.Drawing.Point(390, 470));

            e.Graphics.DrawString("TOTALE:", ValoreFontSmall, System.Drawing.Brushes.Black, new System.Drawing.PointF(2, 490));
            e.Graphics.DrawString(String.Format("{0:0.00} € ({1} prodott{2})", Totale, NumeroProdotti, NumeroProdotti == 1 ? "o" : "i"), ValoreFontSmall, System.Drawing.Brushes.Black, new System.Drawing.PointF(100, 490));

            e.Graphics.DrawString("DATA:", ValoreFontSmall, System.Drawing.Brushes.Black, new System.Drawing.PointF(2, 510));
            e.Graphics.DrawString(String.Format("{0:dd/MM/yyyy HH:mm}", DataOra), ValoreFontSmall, System.Drawing.Brushes.Black, new System.Drawing.PointF(100, 510));

            e.Graphics.DrawString("EVENTO:", ValoreFontSmall, System.Drawing.Brushes.Black, new System.Drawing.PointF(2, 530));
            e.Graphics.DrawString(Management.GetMenuInVigoreSenzaProdotti(DataOra).NomeEvento, ValoreFontSmall, System.Drawing.Brushes.Black, new System.Drawing.PointF(100, 530));
        }

        private void StampaComandaRistorante(PrintPageEventArgs e)
        {
            System.Drawing.Font EtichettaFont = new System.Drawing.Font("Arial", 12);
            System.Drawing.Font PuntoDistribuzioneFont = new System.Drawing.Font("Arial", 16, System.Drawing.FontStyle.Bold);
            System.Drawing.Font EvidenziatoFont = new System.Drawing.Font("Arial", 13, System.Drawing.FontStyle.Bold);
            System.Drawing.Font NoteFont = new System.Drawing.Font("Courier New", 10, System.Drawing.FontStyle.Italic);
            System.Drawing.Font ValoreEquiFont = new System.Drawing.Font("Courier New", 14);
            System.Drawing.Font ValoreFont = new System.Drawing.Font("Arial", 14);
            System.Drawing.Font ValoreFontSmall = new System.Drawing.Font("Arial", 11);

            // 1) Header biglietto [ComandaID | CodiceComanda | Barcode]
            e.Graphics.DrawString("COMANDA: ", EtichettaFont, System.Drawing.Brushes.Black, new System.Drawing.PointF(5, 5));
            e.Graphics.DrawString(ComandaID.ToString().PadLeft(6, '0'), ValoreEquiFont, System.Drawing.Brushes.Black, new System.Drawing.PointF(110, 5));
            e.Graphics.DrawString(Codice.CodiceRaw, new System.Drawing.Font("Arial Black", 30), System.Drawing.Brushes.Red, new System.Drawing.PointF(30, 15));
            iTextSharp.text.pdf.Barcode128 b = new iTextSharp.text.pdf.Barcode128();
            b.Code = new TARLib.Operazioni.Operazione_Comanda(ComandaID.Value).BarcodeString;
            System.Drawing.Image image = b.CreateDrawingImage(System.Drawing.Color.Black, System.Drawing.Color.White);
            e.Graphics.DrawImage(image, 220, 5, 150, 50);
            e.Graphics.DrawLine(System.Drawing.Pens.Black, new System.Drawing.Point(0, 80), new System.Drawing.Point(390, 80));

            // 2) Punto di distribuzione ["Ristorante"]
            e.Graphics.DrawString("Comanda: " + PuntoDiDistribuzione.Descrizione.ToUpper(), PuntoDistribuzioneFont, System.Drawing.Brushes.Black, new System.Drawing.PointF(10, 80));

            e.Graphics.DrawLine(System.Drawing.Pens.Black, new System.Drawing.Point(0, 110), new System.Drawing.Point(390, 110));

            // 3) Area con i prodotti ["Quantita | Descrizione | Importo"]
            // 0, 120 --> 390, 420
            int i = 0;
            if (VociComanda.Count >= 1)
            {
                // Quante comande hanno delle note?
                int NNote = VociComanda.Where(o => !String.IsNullOrEmpty(o.Note)).Count();

                int stepHeight = (300 / (VociComanda.Count + NNote / 2)) < 35 ? (300 / (VociComanda.Count + NNote / 2)) : 35;
                foreach (VoceComanda v in VociComanda)
                {
                    e.Graphics.DrawString(v.Quantita.ToString().PadLeft(2, ' '), ValoreEquiFont, System.Drawing.Brushes.Black, new System.Drawing.PointF(2, 130 + stepHeight * i));

                    e.Graphics.DrawString(v.NomeProdotto, ValoreFont, System.Drawing.Brushes.Black, new System.Drawing.PointF(40, 130 + stepHeight * i));

                    //e.Graphics.DrawString(String.Format("{0:0.00} €", v.SubTotale).PadLeft(8, ' '), ValoreEquiFont, System.Drawing.Brushes.Black, new System.Drawing.PointF(280, 130 + stepHeight * i));

                    if (!String.IsNullOrEmpty(v.Note))
                    {
                        e.Graphics.DrawString(v.Note, NoteFont, System.Drawing.Brushes.Black, new System.Drawing.PointF(45, 130 + stepHeight * ((float)i + (float)0.5)));
                    }

                    i++;
                }
            }

            // 4) Footer ["Ritiro: consegna ai tavoli (Tavolo 10) | DataOra biglietto | Totale biglietto"]

            // Note
            if (!String.IsNullOrEmpty(Note))
            {
                e.Graphics.FillRectangle(System.Drawing.Brushes.LightGray, new System.Drawing.Rectangle(2, 450, 386, 20));
                e.Graphics.DrawString(Note.ToLower(), EvidenziatoFont, System.Drawing.Brushes.Black, new System.Drawing.PointF(5, 451));
            }

            e.Graphics.DrawString("CONSEGNA:", ValoreFontSmall, System.Drawing.Brushes.Black, new System.Drawing.PointF(2, 470));
            string tipoConsegna = "";
            if (!String.IsNullOrEmpty(TavoloAssegnato))
            {
                // Consegna al tavolo
                tipoConsegna = "Al tavolo n° " + TavoloAssegnato;
            }
            else if (IsCheckInRichiesto)
            {
                // Check-in richiesto (Ristorante cascine)
                tipoConsegna = "Check-in alla chiamata della lettera " + Codice.CodiceRaw[0];
            }
            else if (IsStampaRemotaRichiesta)
            {
                // No check-in, stampa remota (Pizzeria)
                tipoConsegna = "Chiamata del codice " + Codice.CodiceRaw + " per consegna";
            }
            else
            {
                // Self service
                tipoConsegna = "SELF SERVICE";
            }
            e.Graphics.DrawString(tipoConsegna, ValoreFontSmall, System.Drawing.Brushes.Black, new System.Drawing.PointF(100, 470));

            e.Graphics.DrawLine(System.Drawing.Pens.Black, new System.Drawing.Point(0, 470), new System.Drawing.Point(390, 470));

            //e.Graphics.DrawString("TOTALE:", ValoreFontSmall, System.Drawing.Brushes.Black, new System.Drawing.PointF(2, 490));
            //e.Graphics.DrawString(String.Format("{0:0.00} € ({1} prodott{2})", Totale, NumeroProdotti, NumeroProdotti == 1 ? "o" : "i"), ValoreFontSmall, System.Drawing.Brushes.Black, new System.Drawing.PointF(100, 490));

            //e.Graphics.DrawString("DATA:", ValoreFontSmall, System.Drawing.Brushes.Black, new System.Drawing.PointF(2, 510));
            //e.Graphics.DrawString(String.Format("{0:dd/MM/yyyy HH:mm}", DataOra), ValoreFontSmall, System.Drawing.Brushes.Black, new System.Drawing.PointF(100, 510));

            //e.Graphics.DrawString("EVENTO:", ValoreFontSmall, System.Drawing.Brushes.Black, new System.Drawing.PointF(2, 530));
            //e.Graphics.DrawString("Festa delle Cascine 2010 - giorno 1", ValoreFontSmall, System.Drawing.Brushes.Black, new System.Drawing.PointF(100, 530));
        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion
    }
}